37장 Set과 Map


Set

집합이다.
배열과 비슷하지만 조금 다름

Untitled 31.png|Untitled 31.png

주요 메서드

new Set(iterable) // set을 만든다. iterable 객체를 전달받으면(대게 배열) 그 안의 값을 복사해서 set에 넣어준다
set.add(value) // value를 추가하고 set 자신을 반환
set.delete(value) // value 제거. 호출 시점에 set 내에 value가 있어서 제거에 성공하면 true, 아니라면 false를 반환
set.has(value) // set 내에 값이 존재하면 true, 아니면 false
set.clear() // set 비우기
set.size // set에 몇 개의 값이 있는지 count

set.keys() // set 내의 모든 값을 포함하는 iterable 객체 반환
set.values() // set.keys와 동일한 작업을 한다. map과의 호환성을 위해 만들어진 메서드
set.entries() // set 내의 각 값을 이용해서 만든 [value, value] 배열을 포함하는 iterable 객체 반환. map과의 호환성을 위해 만들어졌다

set 객체의 생성

Set 생성자 함수로 생성.
Set 생성자 함수는 이터러블을 인수로 전달받아서 Set 객체 생성.

const set1 = new Set([1, 2, 3, 3]);
console.log(set1); // Set(3) {1, 2, 3}

const set2 = new Set('hello');
console.log(set2); // Set(4) {"h", "e", "l", "o"}

요소 개수 확인

Set.prototype.size 프로퍼티로 요소 개수 확인
size 프로퍼티는 getter함수만 존재하는 접근자 프로퍼티
→ 객체 요소 개수 변경 불가.

const set = new Set([1, 2, 3]);

console.log(Object.getOwnPropertyDescriptor(Set.prototype, 'size'));
// {set: undefined, enumerable: false, configurable: true, get: ƒ}

set.size = 10; // 무시된다.
console.log(set.size); // 3

요소 추가

Set.prototype.add 메서드
add 메서드는 새로운 요소 추가된 Set 객체 반환
똑똑한게 NaN, +0, -0 같은 것도 중복된 요소로 추가 되지 않음

const set = new Set();

set.add(1).add(2);
console.log(set); // Set(2) {1, 2}

요소 존재 여부 확인

Set.prototype.has 메서드

const set = new Set([1, 2, 3]);

console.log(set.has(2)); // true
console.log(set.has(4)); // false

요소 삭제

Set.prototype.delete 메서드 사용
삭제하려는 요소값을 인수로 전달
삭제 성공 여부를 불리언 값으로 반

const set = new Set([1, 2, 3]);

// 요소 2를 삭제한다.
set.delete(2);
console.log(set); // Set(2) {1, 3}

// 요소 1을 삭제한다.
set.delete(1);
console.log(set); // Set(1) {3}

요소 일괄 삭제

Set.prototype.clear 메서드
undefined 반환

const set = new Set([1, 2, 3]);

set.clear();
console.log(set); // Set(0) {}

요소 순회

Set.prototype.forEach 메서드 사용

❓ 왜 1번, 2번 인수가 똑같음
⇒ Array.forEach랑 깔맞춤하려고 한거.

const set = new Set([1, 2, 3]);

set.forEach((v, v2, set) => console.log(v, v2, set));
/*
1 1 Set(3) {1, 2, 3}
2 2 Set(3) {1, 2, 3}
3 3 Set(3) {1, 2, 3}
*/

Set 객체는 이터러블이여서 다른 스프레드 문법 등등도 사용가능

const set = new Set([1, 2, 3]);

// Set 객체는 Set.prototype의 Symbol.iterator 메서드를 상속받는 이터러블이다.
console.log(Symbol.iterator in set); // true

// 이터러블인 Set 객체는 for...of 문으로 순회할 수 있다.
for (const value of set) {
  console.log(value); // 1 2 3
}

// 이터러블인 Set 객체는 스프레드 문법의 대상이 될 수 있다.
console.log([...set]); // [1, 2, 3]

// 이터러블인 Set 객체는 배열 디스트럭처링 할당의 대상이 될 수 있다.
const [a, ...rest] = [...set];
console.log(a, rest); // 1, [2, 3]

집합연산

교집합, 차집합, 합집합 가능
부분집합 상위 집합 확인 가능

Map

키와 값의 쌍으로 이루어진 컬렉션이다.
Untitled 1 17.png|Untitled 1 17.png

Object와 Map 비교

Object Map 선택하기

둘 중 어떤 걸 사용하는게 좋을 까

주요 메서드

new Map() // map을 만든다
map.set(key, value) // key를 이용해 value를 저장한다
map.get(key) // key에 해당하는 값 반환. key가 존재하지 않다면 undefined를 반환
map.has(key) // key가 존재하면 true, 아니면 false를 반환
map.delete(key) // key에 해당하는 값 삭제
map.clear() // map 안의 모든 요소 제거
map.size // 요소의 개수 반환

map.keys() // 각 요소의 키를 모아둔 iterable 객체를 반환
map.values() // 각 요소의 값을 모은 iterable 객체를 반환
map.entries() // 요소의 [key, value] 한 쌍으로 하는 iterable 객체 반환. 이 객체는 for...of 루프의 기초로 쓰인다

Map 객체의 생성

Map 생성자 함수로 생성한다.
Map 생성자 함수는 이터러블을 인수로 전달받아 Map 객체 생성.
인수로 전달받은 이터러블은 키와 값의 쌍으로 이루어진 요소로 구성되어야한다.

const map1 = new Map([['key1', 'value1'], ['key2', 'value2']]);
console.log(map1); // Map(2) {"key1" => "value1", "key2" => "value2"}

const map2 = new Map([1, 2]); // TypeError: Iterator value 1 is not an entry object

요소 개수 확인

Map.prototype.size 프로퍼티
마찬가지로 getter 만 가진 접근자 프로퍼티

const { size } = new Map([['key1', 'value1'], ['key2', 'value2']]);
console.log(size); // 2

요소 추가

Map.prototype.set 메서드
새로운 Map 객체 반

const map = new Map();
console.log(map); // Map(0) {}

map.set('key1', 'value1');
console.log(map); // Map(1) {"key1" => "value1"}

Map 객체는 키 타입에 제한이 없다. 모든 값을 키로 사용할 수 있다.
심지어 객체도 키로 사용할 수 있다.

const map = new Map();

const lee = { name: 'Lee' };
const kim = { name: 'Kim' };

// 객체도 키로 사용할 수 있다.
map
  .set(lee, 'developer')
  .set(kim, 'designer');

console.log(map);
// Map(2) { {name: "Lee"} => "developer", {name: "Kim"} => "designer" }

요소 취득

Map.prototype.get 메서드
인수로 전달한 키를 갖는 값을 반환

const map = new Map();

const lee = { name: 'Lee' };
const kim = { name: 'Kim' };

map
  .set(lee, 'developer')
  .set(kim, 'designer');

console.log(map.get(lee)); // developer
console.log(map.get('key')); // undefined

요소 존재 여부 확인

Map.prototype.has

const lee = { name: 'Lee' };
const kim = { name: 'Kim' };

const map = new Map([[lee, 'developer'], [kim, 'designer']]);

console.log(map.has(lee)); // true
console.log(map.has('key')); // false

요소 삭제

Map.prototype.delete 메서드

const lee = { name: 'Lee' };
const kim = { name: 'Kim' };

const map = new Map([[lee, 'developer'], [kim, 'designer']]);

map.delete(kim);
console.log(map); // Map(1) { {name: "Lee"} => "developer" }

요소 일괄 삭제

Map.prototype.clear 메서드

const lee = { name: 'Lee' };
const kim = { name: 'Kim' };

const map = new Map([[lee, 'developer'], [kim, 'designer']]);

map.clear();
console.log(map); // Map(0) {}

요소 순회

Map.prototype.forEach 메서드로 순회

const lee = { name: 'Lee' };
const kim = { name: 'Kim' };

const map = new Map([[lee, 'developer'], [kim, 'designer']]);

map.forEach((v, k, map) => console.log(v, k, map));
/*
developer {name: "Lee"} Map(2) {
  {name: "Lee"} => "developer",
  {name: "Kim"} => "designer"
}
designer {name: "Kim"} Map(2) {
  {name: "Lee"} => "developer",
  {name: "Kim"} => "designer"
}
*/

Map 객체는 이터러블이면서 동시에 이터레이터인 객체를 반환하는 메서드를 제공한다.
Untitled 2 14.png|Untitled 2 14.png

const lee = { name: 'Lee' };
const kim = { name: 'Kim' };

const map = new Map([[lee, 'developer'], [kim, 'designer']]);

// Map.prototype.keys는 Map 객체에서 요소키를 값으로 갖는 이터레이터를 반환한다.
for (const key of map.keys()) {
  console.log(key); // {name: "Lee"} {name: "Kim"}
}

// Map.prototype.values는 Map 객체에서 요소값을 값으로 갖는 이터레이터를 반환한다.
for (const value of map.values()) {
  console.log(value); // developer designer
}

// Map.prototype.entries는 Map 객체에서 요소키와 요소값을 값으로 갖는 이터레이터를 반환한다.
for (const entry of map.entries()) {
  console.log(entry); // [{name: "Lee"}, "developer"]  [{name: "Kim"}, "designer"]
}

reference